using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using CI.Interfaces;

namespace CI.Organism
{
    /// <summary>Organism properties and methods required for processing, eg its dna, neural system</summary>
    public interface IOrganism : IDisposable
    {
        /// <summary>DNA for the Organism</summary>
        IDNA DNA { get; set; }

        /// <summary>Organism's GUID used to uniquely identify it in the Organism</summary>
        Guid Guid { get; }

        /// <summary>This organisms parents</summary>
        SynchronizedCollection<IOrganism> ParentOrganisms { get; }

        /// <summary>Energy Change Event</summary>
        event SynapseIODelegate EnergyChangeEvent;

        /// <summary>Energy Set Event</summary>
        event SynapseIODelegate EnergySetEvent;

        /// <summary>Heartbeat firing</summary>
        event Action HeartbeatChangeEvent;

        /// <summary>Registration of the organism in the enviroment change firing</summary>
        event Action RegistrationChangeEvent;

        /// <summary>Happens when the organism is born</summary>
        event Action BornChangeEvent;

        /// <summary>Happens when the organism changed location</summary>
        event Action<ILocation> LocationChangeEvent;

        /// <summary>Neural network for the Organism</summary>
        INeuralSystem NeuralSystem { get; set; }

        /// <summary>Organisms Heartbeat, this triggers the processing of the DNA</summary>
        void Heartbeat();


        void LocationChange(ILocation location);
        void RegistrationChange();
        void BornChange();

        /// <summary>Terminate Organism, this will usually be because of bad dna, so move it to the dead collection</summary>
        void Terminate(string reason);

        /// <summary>Terminate Organism and move it to the inactive collection, not the dead collection like a normal terminate will do</summary>
        void TerminateAndDestroy(string reason);

        /// <summary>Active state of the Organism. If their eaten etc don't process them</summary>
        ActiveState ActiveState { get; set; }

        /// <summary>Organism energy level, when this gets to 0 the Organism is Dead</summary>
        Int64 Energy { get; set; }

        /// <summary>Organism Init energy level the Organism had at creation</summary>
        Int64 InitEnergy { get; set; }

        /// <summary>Body mass energy, this is the energy left in the Organism once it is dead</summary>
        Int64 BMEnergy { get; set; }

        /// <summary>Collision Impact Energy Transfer, this is how much is taken off a coliding Organism if it is the largest of the two Organism</summary>
        Int64 CIET { get; set; }

        /// <summary>Initial Collision Impact Energy Transfer, this is how much is taken off a coliding Organism if it is the largest of the two Organism</summary>
        Int64 InitCIET { get; set; }

        /// <summary>Calculated fitness value assigned by the fitness function</summary>
        Int64 FitnessValue { get; set; }

        /// <summary>HeartBeat count for the Organism</summary>
        UInt32 HeartbeatCount { get; set; }

        /// <summary>Hosting Environment of the Organism, used to ask for location etc.</summary>
        IHostingEnvironment HostingEnvironment { get; set; }

        /// <summary>Organisms Location, used in collison detection</summary>
        ILocation Location { get; set; }

        /// <summary>
        /// This indicates if the location has changed and also to reset the flag
        /// From this we can decide to redraw maps and calculate collisions
        /// </summary>
        bool LocationDirty { get; set; }

        /// <summary>All the organisms in the environment, the collection it belongs to..</summary>
        IOrganismCollection Organisms { get; set; }

        /// <summary>All the cells in the Organism</summary>
        ICellCollection Cells { get; set; }

        /// <summary>
        /// Has the organism been born yet, they could be in seed type situation and not had the zygote active yet
        /// Usually determined by checking the zygote..
        /// If not born then we dont have to do neural or fitness function
        /// </summary>
        bool Born { get; }

        /// <summary>
        /// do a equals comparison of one organism type to another only comparing the value types, no refference comparisons
        /// </summary>
        /// <param name="organism">organism to compare against</param>
        /// <returns>true if equal value types</returns>
        bool EqualsValueTypes(IOrganism organism);

        /// <summary>
        /// Get the organisms zygote
        /// </summary>
        /// <returns></returns>
        ICell Zygote();

        /// <summary>
        /// Get the SyanpseIO manifest for the organism
        /// </summary>
        /// <returns></returns>
        ReadOnlyCollection<SynapseIO> GetIOManifest();

        /// <summary>
        /// Get the synapseIO with the corresponding binding name
        /// </summary>
        /// <param name="bindingName"></param>
        /// <returns></returns>
        SynapseIO GetSynapseIO(string bindingName);

        /// <summary>
        /// Get the synapseIO with the corresponding Guid
        /// </summary>
        /// <param name="guid"></param>
        /// <returns></returns>
        SynapseIO GetSynapseIO(Guid guid);
    }
}